SCIP Doxygen Documentation
Loading...
Searching...
No Matches
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-2026 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 = calloc(1, 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 = calloc(1, 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
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
1711 for( i = 0; i < CHKHASH_SIZE; ++i )
1712 {
1713 chkmem = blkmem->chkmemhash[i];
1714 while( chkmem != NULL )
1715 {
1716 checkChkmem(chkmem);
1717 tmpmemalloc += ((chkmem->elemsize * chkmem->storesize) + chkmem->nchunks * sizeof(CHUNK) + sizeof(BMS_CHKMEM));
1718 tmpmemused += (chkmem->elemsize * (chkmem->storesize - chkmem->eagerfreesize - chkmem->lazyfreesize));
1719 chkmem = chkmem->nextchkmem;
1720 }
1721 }
1722 assert(tmpmemalloc == blkmem->memallocated);
1723 assert(tmpmemused == blkmem->memused);
1724}
1725#else
1726#define checkBlkmem(blkmem) /**/
1727#endif
1728
1729
1730/** finds the chunk block, to whick the given pointer belongs to
1731 *
1732 * This could be done by selecting the chunk block of the corresponding element size, but in a case of an
1733 * error (free gives an incorrect element size), we want to identify and output the correct element size.
1734 */
1735static
1737 const BMS_BLKMEM* blkmem, /**< block memory */
1738 const void* ptr /**< memory element to search */
1739 )
1740{
1741 BMS_CHKMEM* chkmem;
1742 int i;
1743
1744 assert(blkmem != NULL);
1745
1746 chkmem = NULL;
1747 for( i = 0; chkmem == NULL && i < CHKHASH_SIZE; ++i )
1748 {
1749 chkmem = blkmem->chkmemhash[i];
1750 while( chkmem != NULL && !isPtrInChkmem(chkmem, ptr) )
1751 chkmem = chkmem->nextchkmem;
1752 }
1753
1754 return chkmem;
1755}
1756
1757/** calculates hash number of memory size */
1758static
1760 size_t size /**< element size */
1761 )
1762{
1763 assert(BMSisAligned(size));
1764
1765 return ((uint32_t)size * UINT32_C(0x9e3779b9)) >> (32-CHKHASH_POWER);
1766}
1767
1768/** creates a block memory allocation data structure */
1770 int initchunksize, /**< number of elements in the first chunk of each chunk block */
1771 int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1772 * elements are free (-1: disable garbage collection) */
1773 const char* filename, /**< source file of the function call */
1774 int line /**< line number in source file of the function call */
1775 )
1776{
1777 BMS_BLKMEM* blkmem;
1778 int i;
1779
1780 BMSallocMemory(&blkmem);
1781 if( blkmem != NULL )
1782 {
1783 for( i = 0; i < CHKHASH_SIZE; ++i )
1784 blkmem->chkmemhash[i] = NULL;
1785 blkmem->initchunksize = initchunksize;
1786 blkmem->garbagefactor = garbagefactor;
1787 blkmem->memused = 0;
1788 blkmem->memallocated = 0;
1789 blkmem->maxmemused = 0;
1790 blkmem->maxmemunused = 0;
1791 blkmem->maxmemallocated = 0;
1792 }
1793 else
1794 {
1795 printErrorHeader(filename, line);
1796 printError("Insufficient memory for block memory header.\n");
1797 }
1798
1799 return blkmem;
1800}
1801
1802/** frees all chunk blocks in the block memory */
1804 BMS_BLKMEM* blkmem, /**< block memory */
1805 const char* filename, /**< source file of the function call */
1806 int line /**< line number in source file of the function call */
1807 )
1808{
1809 BMS_CHKMEM* chkmem;
1810 BMS_CHKMEM* nextchkmem;
1811 int i;
1812
1813 if( blkmem != NULL )
1814 {
1815 for( i = 0; i < CHKHASH_SIZE; ++i )
1816 {
1817 chkmem = blkmem->chkmemhash[i];
1818 while( chkmem != NULL )
1819 {
1820 nextchkmem = chkmem->nextchkmem;
1821 destroyChkmem(&chkmem, &blkmem->memallocated);
1822 chkmem = nextchkmem;
1823 }
1824 blkmem->chkmemhash[i] = NULL;
1825 }
1826 blkmem->memused = 0;
1827 assert(blkmem->memallocated == 0);
1828 }
1829 else
1830 {
1831 printErrorHeader(filename, line);
1832 printError("Tried to clear null block memory.\n");
1833 }
1834}
1835
1836/** clears and deletes block memory */
1838 BMS_BLKMEM** blkmem, /**< pointer to block memory */
1839 const char* filename, /**< source file of the function call */
1840 int line /**< line number in source file of the function call */
1841 )
1842{
1843 assert(blkmem != NULL);
1844
1845 if( *blkmem != NULL )
1846 {
1847 BMSclearBlockMemory_call(*blkmem, filename, line);
1848 BMSfreeMemory(blkmem);
1849 assert(*blkmem == NULL);
1850 }
1851 else
1852 {
1853 printErrorHeader(filename, line);
1854 printError("Tried to destroy null block memory.\n");
1855 }
1856}
1857
1858/** work for allocating memory in the block memory pool */
1859INLINE static
1861 BMS_BLKMEM* blkmem, /**< block memory */
1862 size_t size, /**< size of memory element to allocate */
1863 const char* filename, /**< source file of the function call */
1864 int line /**< line number in source file of the function call */
1865 )
1866{
1867 BMS_CHKMEM** chkmemptr;
1868 uint32_t hashnumber;
1869 void* ptr;
1870
1871 assert( blkmem != NULL );
1872
1873 /* allocating very large memory blocks is currently not possible, because BMS_CHKMEM::elemsize is of type int only */
1874 if( size > INT_MAX )
1875 return NULL;
1876
1877 /* calculate hash number of given size */
1878 alignSize(&size);
1879 hashnumber = getHashNumber(size);
1880 assert(hashnumber < CHKHASH_SIZE);
1881
1882 /* find corresponding chunk block */
1883 chkmemptr = &(blkmem->chkmemhash[hashnumber]);
1884 while( *chkmemptr != NULL && (*chkmemptr)->elemsize != (int)size )
1885 chkmemptr = &((*chkmemptr)->nextchkmem);
1886
1887 /* create new chunk block if necessary */
1888 if( *chkmemptr == NULL )
1889 {
1890 *chkmemptr = createChkmem((int)size, blkmem->initchunksize, blkmem->garbagefactor, &blkmem->memallocated);
1891 if( *chkmemptr == NULL )
1892 {
1893 printErrorHeader(filename, line);
1894 printError("Insufficient memory for chunk block.\n");
1895 return NULL;
1896 }
1897#ifndef NDEBUG
1898 BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1899 (*chkmemptr)->line = line;
1900#endif
1901 }
1902#ifndef NDEBUG
1903 else
1904 {
1905 BMSfreeMemoryArrayNull(&(*chkmemptr)->filename);
1906 BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1907 (*chkmemptr)->line = line;
1908 }
1909#endif
1910
1911 /* get memory inside the chunk block */
1912 ptr = allocChkmemElement(*chkmemptr, &blkmem->memallocated);
1913
1914 if( ptr == NULL )
1915 {
1916 printErrorHeader(filename, line);
1917 printError("Insufficient memory for new chunk.\n");
1918 }
1919 debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, ptr, filename, line);
1920
1921 /* add the used memory */
1922 blkmem->memused += (long long) size;
1923 blkmem->maxmemused = MAX(blkmem->maxmemused, blkmem->memused);
1924 blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
1925 blkmem->maxmemallocated = MAX(blkmem->maxmemallocated, blkmem->memallocated);
1926
1927 assert(blkmem->memused >= 0);
1928 assert(blkmem->memallocated >= 0);
1929
1930 checkBlkmem(blkmem);
1931
1932 return ptr;
1933}
1934
1935/** allocates memory in the block memory pool */
1937 BMS_BLKMEM* blkmem, /**< block memory */
1938 size_t size, /**< size of memory element to allocate */
1939 const char* filename, /**< source file of the function call */
1940 int line /**< line number in source file of the function call */
1941 )
1942{
1943#ifndef NDEBUG
1944 if ( size > MAXMEMSIZE )
1945 {
1946 printErrorHeader(filename, line);
1947 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1948 return NULL;
1949 }
1950#endif
1951
1952 return BMSallocBlockMemory_work(blkmem, size, filename, line);
1953}
1954
1955/** allocates memory in the block memory pool and clears it */
1957 BMS_BLKMEM* blkmem, /**< block memory */
1958 size_t size, /**< size of memory element to allocate */
1959 const char* filename, /**< source file of the function call */
1960 int line /**< line number in source file of the function call */
1961 )
1962{
1963 void* ptr;
1964
1965 ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
1966 if( ptr != NULL )
1967 BMSclearMemorySize(ptr, size);
1968
1969 return ptr;
1970}
1971
1972/** allocates array in the block memory pool */
1974 BMS_BLKMEM* blkmem, /**< block memory */
1975 size_t num, /**< size of array to be allocated */
1976 size_t typesize, /**< size of each component */
1977 const char* filename, /**< source file of the function call */
1978 int line /**< line number in source file of the function call */
1979 )
1980{
1981#ifndef NDEBUG
1982 if ( num > (MAXMEMSIZE / typesize) )
1983 {
1984 printErrorHeader(filename, line);
1985 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1986 return NULL;
1987 }
1988#endif
1989
1990 return BMSallocBlockMemory_work(blkmem, num * typesize, filename, line);
1991}
1992
1993/** allocates array in the block memory pool and clears it */
1995 BMS_BLKMEM* blkmem, /**< block memory */
1996 size_t num, /**< size of array to be allocated */
1997 size_t typesize, /**< size of each component */
1998 const char* filename, /**< source file of the function call */
1999 int line /**< line number in source file of the function call */
2000 )
2001{
2002 void* ptr;
2003
2004 ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
2005 if ( ptr != NULL )
2006 BMSclearMemorySize(ptr, num * typesize);
2007
2008 return ptr;
2009}
2010
2011/** resizes memory element in the block memory pool and copies the data */
2013 BMS_BLKMEM* blkmem, /**< block memory */
2014 void* ptr, /**< memory element to reallocated */
2015 size_t oldsize, /**< old size of memory element */
2016 size_t newsize, /**< new size of memory element */
2017 const char* filename, /**< source file of the function call */
2018 int line /**< line number in source file of the function call */
2019 )
2020{
2021 void* newptr;
2022
2023 if( ptr == NULL )
2024 {
2025 assert(oldsize == 0);
2026 return BMSallocBlockMemory_call(blkmem, newsize, filename, line);
2027 }
2028
2029#ifndef NDEBUG
2030 if ( newsize > MAXMEMSIZE )
2031 {
2032 printErrorHeader(filename, line);
2033 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
2034 return NULL;
2035 }
2036#endif
2037
2038 alignSize(&oldsize);
2039 alignSize(&newsize);
2040 if( oldsize == newsize )
2041 return ptr;
2042
2043 newptr = BMSallocBlockMemory_call(blkmem, newsize, filename, line);
2044 if( newptr != NULL )
2045 BMScopyMemorySize(newptr, ptr, MIN(oldsize, newsize));
2046 BMSfreeBlockMemory_call(blkmem, &ptr, oldsize, filename, line);
2047
2048 return newptr;
2049}
2050
2051/** resizes array in the block memory pool and copies the data */
2053 BMS_BLKMEM* blkmem, /**< block memory */
2054 void* ptr, /**< memory element to reallocated */
2055 size_t oldnum, /**< old size of array */
2056 size_t newnum, /**< new size of array */
2057 size_t typesize, /**< size of each component */
2058 const char* filename, /**< source file of the function call */
2059 int line /**< line number in source file of the function call */
2060 )
2061{
2062 void* newptr;
2063
2064 if( ptr == NULL )
2065 {
2066 assert(oldnum == 0);
2067 return BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2068 }
2069
2070#ifndef NDEBUG
2071 if ( newnum > (MAXMEMSIZE / typesize) )
2072 {
2073 printErrorHeader(filename, line);
2074 printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
2075 return NULL;
2076 }
2077#endif
2078
2079 if ( oldnum == newnum )
2080 return ptr;
2081
2082 newptr = BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2083 if ( newptr != NULL )
2084 BMScopyMemorySize(newptr, ptr, MIN(oldnum, newnum) * typesize);
2085 BMSfreeBlockMemory_call(blkmem, &ptr, oldnum * typesize, filename, line);
2086
2087 return newptr;
2088}
2089
2090/** duplicates memory element in the block memory pool and copies the data */
2092 BMS_BLKMEM* blkmem, /**< block memory */
2093 const void* source, /**< memory element to duplicate */
2094 size_t size, /**< size of memory elements */
2095 const char* filename, /**< source file of the function call */
2096 int line /**< line number in source file of the function call */
2097 )
2098{
2099 void* ptr;
2100
2101 assert(source != NULL);
2102
2103 ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
2104 if( ptr != NULL )
2105 BMScopyMemorySize(ptr, source, size);
2106
2107 return ptr;
2108}
2109
2110/** duplicates array in the block memory pool and copies the data */
2112 BMS_BLKMEM* blkmem, /**< block memory */
2113 const void* source, /**< memory element to duplicate */
2114 size_t num, /**< size of array to be duplicated */
2115 size_t typesize, /**< size of each component */
2116 const char* filename, /**< source file of the function call */
2117 int line /**< line number in source file of the function call */
2118 )
2119{
2120 void* ptr;
2121
2122 assert(source != NULL);
2123
2124 ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
2125 if( ptr != NULL )
2126 BMScopyMemorySize(ptr, source, num * typesize);
2127
2128 return ptr;
2129}
2130
2131/** common work for freeing block memory */
2132INLINE static
2134 BMS_BLKMEM* blkmem, /**< block memory */
2135 void** ptr, /**< pointer to pointer to memory element to free */
2136 size_t size, /**< size of memory element */
2137 const char* filename, /**< source file of the function call */
2138 int line /**< line number in source file of the function call */
2139 )
2140{
2141 BMS_CHKMEM* chkmem;
2142 uint32_t hashnumber;
2143
2144 assert(ptr != NULL);
2145 assert(*ptr != NULL);
2146
2147 /* calculate hash number of given size */
2148 alignSize(&size);
2149 hashnumber = getHashNumber(size);
2150 assert(hashnumber < CHKHASH_SIZE);
2151
2152 debugMessage("free %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, *ptr, filename, line);
2153
2154 /* find corresponding chunk block */
2155 chkmem = blkmem->chkmemhash[hashnumber];
2156 while( chkmem != NULL && chkmem->elemsize != (int)size )
2157 chkmem = chkmem->nextchkmem;
2158 if( chkmem == NULL )
2159 {
2160 printErrorHeader(filename, line);
2161 printError("Tried to free pointer <%p> in block memory <%p> of unknown size %llu.\n", *ptr, (void*)blkmem, (unsigned long long)size);
2162 return;
2163 }
2164 assert(chkmem->elemsize == (int)size);
2165
2166 /* free memory in chunk block */
2167 freeChkmemElement(chkmem, *ptr, &blkmem->memallocated, filename, line);
2168 blkmem->memused -= (long long) size;
2169
2170 blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
2171
2172 assert(blkmem->memused >= 0);
2173 assert(blkmem->memallocated >= 0);
2174
2175 checkBlkmem(blkmem);
2176
2177 *ptr = NULL;
2178}
2179
2180/** frees memory element in the block memory pool and sets pointer to NULL */
2182 BMS_BLKMEM* blkmem, /**< block memory */
2183 void** ptr, /**< pointer to pointer to memory element to free */
2184 size_t size, /**< size of memory element */
2185 const char* filename, /**< source file of the function call */
2186 int line /**< line number in source file of the function call */
2187 )
2188{
2189 assert( blkmem != NULL );
2190 assert( ptr != NULL );
2191
2192 if( *ptr != NULL )
2193 BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2194 else if( size != 0 )
2195 {
2196 printErrorHeader(filename, line);
2197 printError("Tried to free null block pointer.\n");
2198 }
2199 checkBlkmem(blkmem);
2200}
2201
2202/** frees memory element in the block memory pool if pointer is not NULL and sets pointer to NULL */
2204 BMS_BLKMEM* blkmem, /**< block memory */
2205 void** ptr, /**< pointer to pointer to memory element to free */
2206 size_t size, /**< size of memory element */
2207 const char* filename, /**< source file of the function call */
2208 int line /**< line number in source file of the function call */
2209 )
2210{
2211 assert( blkmem != NULL );
2212 assert( ptr != NULL );
2213
2214 if( *ptr != NULL )
2215 {
2216 BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2217 }
2218 checkBlkmem(blkmem);
2219}
2220
2221/** calls garbage collection of block memory, frees chunks without allocated memory elements, and frees
2222 * chunk blocks without any chunks
2223 */
2225 BMS_BLKMEM* blkmem /**< block memory */
2226 )
2227{
2228 int i;
2229
2230 assert(blkmem != NULL);
2231
2232 for( i = 0; i < CHKHASH_SIZE; ++i )
2233 {
2234 BMS_CHKMEM** chkmemptr;
2235
2236 chkmemptr = &blkmem->chkmemhash[i];
2237 while( *chkmemptr != NULL )
2238 {
2239 garbagecollectChkmem(*chkmemptr, &blkmem->memallocated);
2240 checkBlkmem(blkmem);
2241 if( (*chkmemptr)->nchunks == 0 )
2242 {
2243 BMS_CHKMEM* nextchkmem;
2244
2245 assert((*chkmemptr)->lazyfreesize == 0);
2246 nextchkmem = (*chkmemptr)->nextchkmem;
2247 destroyChkmem(chkmemptr, &blkmem->memallocated);
2248 *chkmemptr = nextchkmem;
2249 checkBlkmem(blkmem);
2250 }
2251 else
2252 chkmemptr = &(*chkmemptr)->nextchkmem;
2253 }
2254 }
2255}
2256
2257/** returns the number of allocated bytes in the block memory */
2259 const BMS_BLKMEM* blkmem /**< block memory */
2260 )
2261{
2262 assert( blkmem != NULL );
2263
2264 return blkmem->memallocated;
2265}
2266
2267/** returns the number of used bytes in the block memory */
2269 const BMS_BLKMEM* blkmem /**< block memory */
2270 )
2271{
2272 assert( blkmem != NULL );
2273
2274 return blkmem->memused;
2275}
2276
2277/** returns the number of allocated but not used bytes in the block memory */
2279 const BMS_BLKMEM* blkmem /**< block memory */
2280 )
2281{
2282 assert( blkmem != NULL );
2283
2284 return blkmem->memallocated - blkmem->memused;
2285}
2286
2287/** returns the maximal number of used bytes in the block memory */
2289 const BMS_BLKMEM* blkmem /**< block memory */
2290 )
2291{
2292 assert( blkmem != NULL );
2293
2294 return blkmem->maxmemused;
2295}
2296
2297/** returns the maximal number of allocated but not used bytes in the block memory */
2299 const BMS_BLKMEM* blkmem /**< block memory */
2300 )
2301{
2302 assert( blkmem != NULL );
2303
2304 return blkmem->maxmemunused;
2305}
2306
2307/** returns the maximal number of allocated bytes in the block memory */
2309 const BMS_BLKMEM* blkmem /**< block memory */
2310 )
2311{
2312 assert( blkmem != NULL );
2313
2314 return blkmem->maxmemallocated;
2315}
2316
2317/** returns the size of the given memory element; returns 0, if the element is not member of the block memory */
2319 const BMS_BLKMEM* blkmem, /**< block memory */
2320 const void* ptr /**< memory element */
2321 )
2322{
2323 const BMS_CHKMEM* chkmem;
2324
2325 assert(blkmem != NULL);
2326
2327 if( ptr == NULL )
2328 return 0;
2329
2330 chkmem = findChkmem(blkmem, ptr);
2331 if( chkmem == NULL )
2332 return 0;
2333
2334 return (size_t)(chkmem->elemsize); /*lint !e571*/
2335}
2336
2337/** outputs allocation diagnostics of block memory */
2339 const BMS_BLKMEM* blkmem /**< block memory */
2340 )
2341{
2342 const BMS_CHKMEM* chkmem;
2343 int nblocks = 0;
2344 int nunusedblocks = 0;
2345 int totalnchunks = 0;
2346 int totalneagerchunks = 0;
2347 int totalnelems = 0;
2348 int totalneagerelems = 0;
2349 int totalnlazyelems = 0;
2350#ifndef NDEBUG
2351 int totalngarbagecalls = 0;
2352 int totalngarbagefrees = 0;
2353#endif
2354 long long allocedmem = 0;
2355 long long freemem = 0;
2356 int i;
2357
2358#ifndef NDEBUG
2359 printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr #GCl #GFr Free MBytes First Allocator\n");
2360#else
2361 printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr Free MBytes\n");
2362#endif
2363
2364 assert(blkmem != NULL);
2365
2366 for( i = 0; i < CHKHASH_SIZE; ++i )
2367 {
2368 chkmem = blkmem->chkmemhash[i];
2369 while( chkmem != NULL )
2370 {
2371 int nchunks = 0;
2372 int nelems = 0;
2373 int neagerchunks = 0;
2374 int neagerelems = 0;
2375
2376 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
2377 {
2378 assert(chunk != NULL);
2379 assert(chunk->elemsize == chkmem->elemsize);
2380 assert(chunk->chkmem == chkmem);
2381 nchunks++;
2382 nelems += chunk->storesize;
2383 if( chunk->eagerfree != NULL )
2384 {
2385 neagerchunks++;
2386 neagerelems += chunk->eagerfreesize;
2387 }
2388 })
2389
2390 assert(nchunks == chkmem->nchunks);
2391 assert(nelems == chkmem->storesize);
2392 assert(neagerelems == chkmem->eagerfreesize);
2393
2394 if( nelems > 0 )
2395 {
2396 nblocks++;
2397 allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2398 freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2399
2400#ifndef NDEBUG
2401 printInfo("%7d %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f %s:%d\n",
2402 chkmem->elemsize, nchunks, neagerchunks, nelems,
2403 neagerelems, chkmem->lazyfreesize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2404 100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2405 (double)chkmem->elemsize * nelems / (1024.0*1024.0),
2406 chkmem->filename, chkmem->line);
2407#else
2408 printInfo("%7d %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2409 chkmem->elemsize, nchunks, neagerchunks, nelems,
2410 neagerelems, chkmem->lazyfreesize,
2411 100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2412 (double)chkmem->elemsize * nelems / (1024.0*1024.0));
2413#endif
2414 }
2415 else
2416 {
2417#ifndef NDEBUG
2418 printInfo("%7d <unused> %5d %4d %s:%d\n",
2419 chkmem->elemsize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2420 chkmem->filename, chkmem->line);
2421#else
2422 printInfo("%7d <unused>\n", chkmem->elemsize);
2423#endif
2424 nunusedblocks++;
2425 }
2426 totalnchunks += nchunks;
2427 totalneagerchunks += neagerchunks;
2428 totalnelems += nelems;
2429 totalneagerelems += neagerelems;
2430 totalnlazyelems += chkmem->lazyfreesize;
2431#ifndef NDEBUG
2432 totalngarbagecalls += chkmem->ngarbagecalls;
2433 totalngarbagefrees += chkmem->ngarbagefrees;
2434#endif
2435 chkmem = chkmem->nextchkmem;
2436 }
2437 }
2438#ifndef NDEBUG
2439 printInfo(" Total %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f\n",
2440 totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
2441 totalngarbagecalls, totalngarbagefrees,
2442 totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2443 (double)allocedmem/(1024.0*1024.0));
2444#else
2445 printInfo(" Total %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2446 totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
2447 totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2448 (double)allocedmem/(1024.0*1024.0));
2449#endif
2450 printInfo("%d blocks (%d unused), %" LONGINT_FORMAT " bytes allocated, %" LONGINT_FORMAT " bytes free", /* cppcheck-suppress syntaxError */
2451 nblocks + nunusedblocks, nunusedblocks, allocedmem, freemem);
2452 if( allocedmem > 0 )
2453 printInfo(" (%.1f%%)", 100.0 * (double) freemem / (double) allocedmem);
2454 printInfo("\n\n");
2455
2456 printInfo("Memory Peaks: Used Lazy Total\n");
2457 printInfo(" %6.1f %6.1f %6.1f MBytes\n", (double)blkmem->maxmemused / (1024.0 * 1024.0),
2458 (double)blkmem->maxmemunused / (1024.0 * 1024.0), (double)blkmem->maxmemallocated / (1024.0 * 1024.0));
2459}
2460
2461/** outputs error messages, if there are allocated elements in the block memory and returns number of unfreed bytes */
2463 const BMS_BLKMEM* blkmem /**< block memory */
2464 )
2465{
2466 const BMS_CHKMEM* chkmem;
2467 long long allocedmem = 0;
2468 long long freemem = 0;
2469 int i;
2470
2471 assert(blkmem != NULL);
2472
2473 for( i = 0; i < CHKHASH_SIZE; ++i )
2474 {
2475 chkmem = blkmem->chkmemhash[i];
2476 while( chkmem != NULL )
2477 {
2478 int nchunks = 0;
2479 int nelems = 0;
2480 int neagerelems = 0;
2481
2482 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
2483 {
2484 assert(chunk != NULL);
2485 assert(chunk->elemsize == chkmem->elemsize);
2486 assert(chunk->chkmem == chkmem);
2487 nchunks++;
2488 nelems += chunk->storesize;
2489 if( chunk->eagerfree != NULL )
2490 neagerelems += chunk->eagerfreesize;
2491 })
2492
2493 assert(nchunks == chkmem->nchunks);
2494 SCIP_UNUSED(nchunks);
2495 assert(nelems == chkmem->storesize);
2496 assert(neagerelems == chkmem->eagerfreesize);
2497
2498 if( nelems > 0 )
2499 {
2500 allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2501 freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2502
2503 if( nelems != neagerelems + chkmem->lazyfreesize )
2504 {
2505#ifndef NDEBUG
2506 errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed. First Allocator: %s:%d\n",
2507 (((long long)nelems - (long long)neagerelems) - (long long)chkmem->lazyfreesize)
2508 * (long long)(chkmem->elemsize),
2509 (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize),
2510 chkmem->filename, chkmem->line);
2511#else
2512 errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed.\n",
2513 ((nelems - neagerelems) - chkmem->lazyfreesize) * (long long)(chkmem->elemsize),
2514 (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize));
2515#endif
2516 }
2517 }
2518 chkmem = chkmem->nextchkmem;
2519 }
2520 }
2521
2522 if( allocedmem != freemem )
2523 {
2524 errorMessage("%" LONGINT_FORMAT " bytes not freed in total.\n", allocedmem - freemem);
2525 }
2526
2527 return allocedmem - freemem;
2528}
2529
2530
2531
2532
2533
2534
2535/***********************************************************
2536 * Buffer Memory Management
2537 *
2538 * Efficient memory management for temporary objects
2539 ***********************************************************/
2540
2541/** memory buffer storage for temporary objects */
2543{
2544 void** data; /**< allocated memory chunks for arbitrary data */
2545 size_t* size; /**< sizes of buffers in bytes */
2546 unsigned int* used; /**< 1 iff corresponding buffer is in use */
2547 size_t totalmem; /**< total memory consumption of buffer */
2548 unsigned int clean; /**< 1 iff the memory blocks in the buffer should be initialized to zero? */
2549 size_t ndata; /**< number of memory chunks */
2550 size_t firstfree; /**< first unused memory chunk */
2551 double arraygrowfac; /**< memory growing factor for dynamically allocated arrays */
2552 unsigned int arraygrowinit; /**< initial size of dynamically allocated arrays */
2553};
2554
2555
2556/** creates memory buffer storage */
2558 double arraygrowfac, /**< memory growing factor for dynamically allocated arrays */
2559 int arraygrowinit, /**< initial size of dynamically allocated arrays */
2560 unsigned int clean, /**< should the memory blocks in the buffer be initialized to zero? */
2561 const char* filename, /**< source file of the function call */
2562 int line /**< line number in source file of the function call */
2563 )
2564{
2565 BMS_BUFMEM* buffer;
2566
2567 assert( arraygrowinit > 0 );
2568 assert( arraygrowfac > 0.0 );
2569
2570 BMSallocMemory(&buffer);
2571 if ( buffer != NULL )
2572 {
2573 buffer->data = NULL;
2574 buffer->size = NULL;
2575 buffer->used = NULL;
2576 buffer->totalmem = 0UL;
2577 buffer->clean = clean;
2578 buffer->ndata = 0;
2579 buffer->firstfree = 0;
2580 buffer->arraygrowinit = (unsigned) arraygrowinit;
2581 buffer->arraygrowfac = arraygrowfac;
2582 }
2583 else
2584 {
2585 printErrorHeader(filename, line);
2586 printError("Insufficient memory for buffer memory header.\n");
2587 }
2588
2589 return buffer;
2590}
2591
2592/** destroys buffer memory */
2594 BMS_BUFMEM** buffer, /**< pointer to memory buffer storage */
2595 const char* filename, /**< source file of the function call */
2596 int line /**< line number in source file of the function call */
2597 )
2598{
2599 size_t i;
2600
2601 if ( *buffer != NULL )
2602 {
2603 i = (*buffer)->ndata;
2604 if ( i > 0 ) {
2605 for (--i ; ; i--)
2606 {
2607 assert( ! (*buffer)->used[i] );
2608 BMSfreeMemoryArrayNull(&(*buffer)->data[i]);
2609 if ( i == 0 )
2610 break;
2611 }
2612 }
2613 BMSfreeMemoryArrayNull(&(*buffer)->data);
2614 BMSfreeMemoryArrayNull(&(*buffer)->size);
2615 BMSfreeMemoryArrayNull(&(*buffer)->used);
2616 BMSfreeMemory(buffer);
2617 }
2618 else
2619 {
2620 printErrorHeader(filename, line);
2621 printError("Tried to free null buffer memory.\n");
2622 }
2623}
2624
2625/** set arraygrowfac */
2627 BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
2628 double arraygrowfac /**< memory growing factor for dynamically allocated arrays */
2629 )
2630{
2631 assert( buffer != NULL );
2632 assert( arraygrowfac > 0.0 );
2633
2634 buffer->arraygrowfac = arraygrowfac;
2635}
2636
2637/** set arraygrowinit */
2639 BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
2640 int arraygrowinit /**< initial size of dynamically allocated arrays */
2641 )
2642{
2643 assert( buffer != NULL );
2644 assert( arraygrowinit > 0 );
2645
2646 buffer->arraygrowinit = (unsigned) arraygrowinit;
2647}
2648
2649#ifndef SCIP_NOBUFFERMEM
2650/** calculate memory size for dynamically allocated arrays
2651 *
2652 * This function is a copy of the function in set.c in order to be able to use memory.? separately.
2653 */
2654static
2656 size_t initsize, /**< initial size of array */
2657 SCIP_Real growfac, /**< growing factor of array */
2658 size_t num /**< minimum number of entries to store */
2659 )
2660{
2661 size_t size;
2662
2663 assert( growfac >= 1.0 );
2664
2665 if ( growfac == 1.0 )
2666 size = MAX(initsize, num);
2667 else
2668 {
2669 size_t oldsize;
2670
2671 /* calculate the size with this loop, such that the resulting numbers are always the same */
2672 initsize = MAX(initsize, 4);
2673 size = initsize;
2674 oldsize = size - 1;
2675
2676 /* second condition checks against overflow */
2677 while ( size < num && size > oldsize )
2678 {
2679 oldsize = size;
2680 size = (size_t)(growfac * size + initsize);
2681 }
2682
2683 /* if an overflow happened, set the correct value */
2684 if ( size <= oldsize )
2685 size = num;
2686 }
2687
2688 assert( size >= initsize );
2689 assert( size >= num );
2690
2691 return size;
2692}
2693#endif
2694
2695/** work for allocating the next unused buffer */
2696INLINE static
2698 BMS_BUFMEM* buffer, /**< memory buffer storage */
2699 size_t size, /**< minimal required size of the buffer */
2700 const char* filename, /**< source file of the function call */
2701 int line /**< line number in source file of the function call */
2702 )
2703{
2704 void* ptr;
2705#ifndef SCIP_NOBUFFERMEM
2706 size_t bufnum;
2707#endif
2708
2709#ifndef SCIP_NOBUFFERMEM
2710 assert( buffer != NULL );
2711 assert( buffer->firstfree <= buffer->ndata );
2712
2713 /* allocate a minimum of 1 byte */
2714 if ( size == 0 )
2715 size = 1;
2716
2717 /* check, if we need additional buffers */
2718 if ( buffer->firstfree == buffer->ndata )
2719 {
2720 size_t newsize;
2721 size_t i;
2722
2723 /* create additional buffers */
2724 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, buffer->firstfree + 1);
2725 BMSreallocMemoryArray(&buffer->data, newsize);
2726 if ( buffer->data == NULL )
2727 {
2728 printErrorHeader(filename, line);
2729 printError("Insufficient memory for reallocating buffer data storage.\n");
2730 return NULL;
2731 }
2732 BMSreallocMemoryArray(&buffer->size, newsize);
2733 if ( buffer->size == NULL )
2734 {
2735 printErrorHeader(filename, line);
2736 printError("Insufficient memory for reallocating buffer size storage.\n");
2737 return NULL;
2738 }
2739 BMSreallocMemoryArray(&buffer->used, newsize);
2740 if ( buffer->used == NULL )
2741 {
2742 printErrorHeader(filename, line);
2743 printError("Insufficient memory for reallocating buffer used storage.\n");
2744 return NULL;
2745 }
2746
2747 /* init data */
2748 for (i = buffer->ndata; i < newsize; ++i)
2749 {
2750 buffer->data[i] = NULL;
2751 buffer->size[i] = 0;
2752 buffer->used[i] = FALSE;
2753 }
2754 buffer->ndata = newsize;
2755 }
2756 assert(buffer->firstfree < buffer->ndata);
2757
2758 /* check, if the current buffer is large enough */
2759 bufnum = buffer->firstfree;
2760 assert( ! buffer->used[bufnum] );
2761 if ( buffer->size[bufnum] < size )
2762 {
2763 size_t newsize;
2764
2765 /* enlarge buffer */
2766 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2767 BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2768
2769 /* clear new memory */
2770 if( buffer->clean )
2771 {
2772 char* tmpptr = (char*)(buffer->data[bufnum]);
2773 size_t inc = buffer->size[bufnum] / sizeof(*tmpptr);
2774 tmpptr += inc;
2775
2776 BMSclearMemorySize(tmpptr, newsize - buffer->size[bufnum]);
2777 }
2778 assert( newsize > buffer->size[bufnum] );
2779 buffer->totalmem += newsize - buffer->size[bufnum];
2780 buffer->size[bufnum] = newsize;
2781
2782 if ( buffer->data[bufnum] == NULL )
2783 {
2784 printErrorHeader(filename, line);
2785 printError("Insufficient memory for reallocating buffer storage.\n");
2786 return NULL;
2787 }
2788 }
2789 assert( buffer->size[bufnum] >= size );
2790
2791#ifdef CHECKCLEANBUFFER
2792 /* check that the memory is cleared */
2793 if( buffer->clean )
2794 checkCleanmem(buffer->data[bufnum], buffer->size[bufnum]);
2795#endif
2796
2797 ptr = buffer->data[bufnum];
2798 buffer->used[bufnum] = TRUE;
2799 buffer->firstfree++;
2800
2801 debugMessage("Allocated buffer %llu/%llu at %p of size %llu (required size: %llu) for pointer %p.\n",
2802 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2803 (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, ptr);
2804
2805#else
2806 if( buffer->clean )
2807 {
2808 /* we should allocate at least one byte, otherwise BMSallocMemorySize will fail */
2809 size = MAX(size,1);
2810
2811 BMSallocClearMemorySize(&ptr, size);
2812 }
2813 else
2814 {
2815 BMSallocMemorySize(&ptr, size);
2816 }
2817#endif
2818
2819 return ptr;
2820}
2821
2822/** allocates the next unused buffer */
2824 BMS_BUFMEM* buffer, /**< memory buffer storage */
2825 size_t size, /**< minimal required size of the buffer */
2826 const char* filename, /**< source file of the function call */
2827 int line /**< line number in source file of the function call */
2828 )
2829{
2830#ifndef NDEBUG
2831 if ( size > MAXMEMSIZE )
2832 {
2833 printErrorHeader(filename, line);
2834 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2835 return NULL;
2836 }
2837#endif
2838
2839 return BMSallocBufferMemory_work(buffer, size, filename, line);
2840}
2841
2842/** allocates the next unused buffer array */
2844 BMS_BUFMEM* buffer, /**< memory buffer storage */
2845 size_t num, /**< size of array to be allocated */
2846 size_t typesize, /**< size of components */
2847 const char* filename, /**< source file of the function call */
2848 int line /**< line number in source file of the function call */
2849 )
2850{
2851#ifndef NDEBUG
2852 if ( num > (MAXMEMSIZE / typesize) )
2853 {
2854 printErrorHeader(filename, line);
2855 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2856 return NULL;
2857 }
2858#endif
2859
2860 return BMSallocBufferMemory_work(buffer, num * typesize, filename, line);
2861}
2862
2863/** allocates the next unused buffer and clears it */
2865 BMS_BUFMEM* buffer, /**< memory buffer storage */
2866 size_t num, /**< size of array to be allocated */
2867 size_t typesize, /**< size of components */
2868 const char* filename, /**< source file of the function call */
2869 int line /**< line number in source file of the function call */
2870 )
2871{
2872 void* ptr;
2873
2874 ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
2875 if ( ptr != NULL )
2876 BMSclearMemorySize(ptr, num * typesize);
2877
2878 return ptr;
2879}
2880
2881/** work for reallocating the buffer to at least the given size */
2882INLINE static
2884 BMS_BUFMEM* buffer, /**< memory buffer storage */
2885 void* ptr, /**< pointer to the allocated memory buffer */
2886 size_t size, /**< minimal required size of the buffer */
2887 const char* filename, /**< source file of the function call */
2888 int line /**< line number in source file of the function call */
2889 )
2890{
2891 void* newptr;
2892#ifndef SCIP_NOBUFFERMEM
2893 size_t bufnum;
2894#endif
2895
2896#ifndef SCIP_NOBUFFERMEM
2897 assert( buffer != NULL );
2898 assert( buffer->firstfree <= buffer->ndata );
2899 assert(!buffer->clean); /* reallocating clean buffer elements is not supported */
2900
2901 /* if the pointer doesn't exist yet, allocate it */
2902 if ( ptr == NULL )
2903 return BMSallocBufferMemory_call(buffer, size, filename, line);
2904
2905 assert( buffer->firstfree >= 1 );
2906
2907 /* Search the pointer in the buffer list:
2908 * Usually, buffers are allocated and freed like a stack, such that the currently used pointer is
2909 * most likely at the end of the buffer list.
2910 */
2911 bufnum = buffer->firstfree - 1;
2912 while ( bufnum > 0 && buffer->data[bufnum] != ptr )
2913 --bufnum;
2914
2915 newptr = ptr;
2916 assert( buffer->data[bufnum] == newptr );
2917 assert( buffer->used[bufnum] );
2918 assert( buffer->size[bufnum] >= 1 );
2919
2920 /* check if the buffer has to be enlarged */
2921 if ( size > buffer->size[bufnum] )
2922 {
2923 size_t newsize;
2924
2925 /* enlarge buffer */
2926 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2927 BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2928 assert( newsize > buffer->size[bufnum] );
2929 buffer->totalmem += newsize - buffer->size[bufnum];
2930 buffer->size[bufnum] = newsize;
2931 if ( buffer->data[bufnum] == NULL )
2932 {
2933 printErrorHeader(filename, line);
2934 printError("Insufficient memory for reallocating buffer storage.\n");
2935 return NULL;
2936 }
2937 newptr = buffer->data[bufnum];
2938 }
2939 assert( buffer->size[bufnum] >= size );
2940 assert( newptr == buffer->data[bufnum] );
2941
2942 debugMessage("Reallocated buffer %llu/%llu at %p to size %llu (required size: %llu) for pointer %p.\n",
2943 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2944 (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, newptr);
2945
2946#else
2947 newptr = ptr;
2948 BMSreallocMemorySize(&newptr, size);
2949#endif
2950
2951 return newptr;
2952}
2953
2954/** reallocates the buffer to at least the given size */
2956 BMS_BUFMEM* buffer, /**< memory buffer storage */
2957 void* ptr, /**< pointer to the allocated memory buffer */
2958 size_t size, /**< minimal required size of the buffer */
2959 const char* filename, /**< source file of the function call */
2960 int line /**< line number in source file of the function call */
2961 )
2962{
2963#ifndef NDEBUG
2964 if ( size > MAXMEMSIZE )
2965 {
2966 printErrorHeader(filename, line);
2967 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2968 return NULL;
2969 }
2970#endif
2971
2972 return BMSreallocBufferMemory_work(buffer, ptr, size, filename, line);
2973}
2974
2975/** reallocates an array in the buffer to at least the given size */
2977 BMS_BUFMEM* buffer, /**< memory buffer storage */
2978 void* ptr, /**< pointer to the allocated memory buffer */
2979 size_t num, /**< size of array to be allocated */
2980 size_t typesize, /**< size of components */
2981 const char* filename, /**< source file of the function call */
2982 int line /**< line number in source file of the function call */
2983 )
2984{
2985#ifndef NDEBUG
2986 if ( num > (MAXMEMSIZE / typesize) )
2987 {
2988 printErrorHeader(filename, line);
2989 printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
2990 return NULL;
2991 }
2992#endif
2993
2994 return BMSreallocBufferMemory_work(buffer, ptr, num * typesize, filename, line);
2995}
2996
2997/** allocates the next unused buffer and copies the given memory into the buffer */
2999 BMS_BUFMEM* buffer, /**< memory buffer storage */
3000 const void* source, /**< memory block to copy into the buffer */
3001 size_t size, /**< minimal required size of the buffer */
3002 const char* filename, /**< source file of the function call */
3003 int line /**< line number in source file of the function call */
3004 )
3005{
3006 void* ptr;
3007
3008 assert( source != NULL );
3009
3010 /* allocate a buffer of the given size */
3011 ptr = BMSallocBufferMemory_call(buffer, size, filename, line);
3012
3013 /* copy the source memory into the buffer */
3014 if ( ptr != NULL )
3015 BMScopyMemorySize(ptr, source, size);
3016
3017 return ptr;
3018}
3019
3020/** allocates an array in the next unused buffer and copies the given memory into the buffer */
3022 BMS_BUFMEM* buffer, /**< memory buffer storage */
3023 const void* source, /**< memory block to copy into the buffer */
3024 size_t num, /**< size of array to be allocated */
3025 size_t typesize, /**< size of components */
3026 const char* filename, /**< source file of the function call */
3027 int line /**< line number in source file of the function call */
3028 )
3029{
3030 void* ptr;
3031
3032 assert( source != NULL );
3033
3034 /* allocate a buffer of the given size */
3035 ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
3036
3037 /* copy the source memory into the buffer */
3038 if ( ptr != NULL )
3039 BMScopyMemorySize(ptr, source, num * typesize);
3040
3041 return ptr;
3042}
3043
3044/** work for freeing a buffer */
3045INLINE static
3047 BMS_BUFMEM* buffer, /**< memory buffer storage */
3048 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3049 const char* filename, /**< source file of the function call */
3050 int line /**< line number in source file of the function call */
3051 )
3052{ /*lint --e{715}*/
3053 size_t bufnum;
3054
3055 assert( buffer != NULL );
3056 assert( buffer->firstfree <= buffer->ndata );
3057 assert( buffer->firstfree >= 1 );
3058 assert( ptr != NULL );
3059 assert( *ptr != NULL );
3060
3061 /* Search the pointer in the buffer list:
3062 * Usually, buffers are allocated and freed like a stack, such that the freed pointer is
3063 * most likely at the end of the buffer list.
3064 */
3065 bufnum = buffer->firstfree-1;
3066 while ( bufnum > 0 && buffer->data[bufnum] != *ptr )
3067 --bufnum;
3068
3069#ifdef CHECKBUFFERORDER
3070 if ( bufnum < buffer->firstfree - 1 )
3071 {
3072 warningMessage("[%s:%d]: freeing buffer in wrong order.\n", filename, line);
3073 }
3074#endif
3075
3076#ifndef NDEBUG
3077 if ( bufnum == 0 && buffer->data[bufnum] != *ptr )
3078 {
3079 printErrorHeader(filename, line);
3080 printError("Tried to free unknown buffer pointer.\n");
3081 return;
3082 }
3083 if ( ! buffer->used[bufnum] )
3084 {
3085 printErrorHeader(filename, line);
3086 printError("Tried to free buffer pointer already freed.\n");
3087 return;
3088 }
3089#endif
3090
3091#ifdef CHECKCLEANBUFFER
3092 /* check that the memory is cleared */
3093 if( buffer->clean )
3094 checkCleanmem(buffer->data[bufnum], buffer->size[bufnum]);
3095#endif
3096
3097 assert( buffer->data[bufnum] == *ptr );
3098 buffer->used[bufnum] = FALSE;
3099
3100 while ( buffer->firstfree > 0 && !buffer->used[buffer->firstfree-1] )
3101 --buffer->firstfree;
3102
3103 debugMessage("Freed buffer %llu/%llu at %p of size %llu for pointer %p, first free is %llu.\n",
3104 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
3105 (unsigned long long)(buffer->size[bufnum]), *ptr, (unsigned long long)(buffer->firstfree));
3106
3107 *ptr = NULL;
3108}
3109
3110/** frees a buffer and sets pointer to NULL */
3112 BMS_BUFMEM* buffer, /**< memory buffer storage */
3113 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3114 const char* filename, /**< source file of the function call */
3115 int line /**< line number in source file of the function call */
3116 )
3117{ /*lint --e{715}*/
3118 assert( ptr != NULL );
3119
3120#ifndef SCIP_NOBUFFERMEM
3121 if ( *ptr != NULL )
3122 BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3123 else
3124 {
3125 printErrorHeader(filename, line);
3126 printError("Tried to free null buffer pointer.\n");
3127 }
3128#else
3129 BMSfreeMemory(ptr);
3130#endif
3131}
3132
3133/** frees a buffer if pointer is not NULL and sets pointer to NULL */
3135 BMS_BUFMEM* buffer, /**< memory buffer storage */
3136 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3137 const char* filename, /**< source file of the function call */
3138 int line /**< line number in source file of the function call */
3139 )
3140{ /*lint --e{715}*/
3141 assert( ptr != NULL );
3142
3143 if ( *ptr != NULL )
3144 {
3145#ifndef SCIP_NOBUFFERMEM
3146 BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3147#else
3148 BMSfreeMemory(ptr);
3149#endif
3150 }
3151}
3152
3153/** gets number of used buffers */
3155 BMS_BUFMEM* buffer /**< memory buffer storage */
3156 )
3157{
3158 assert( buffer != NULL );
3159
3160 return buffer->firstfree;
3161}
3162
3163/** returns the number of allocated bytes in the buffer memory */
3165 const BMS_BUFMEM* buffer /**< buffer memory */
3166 )
3167{
3168#ifdef CHECKMEM
3169 size_t totalmem = 0UL;
3170 size_t i;
3171
3172 assert( buffer != NULL );
3173 for (i = 0; i < buffer->ndata; ++i)
3174 totalmem += buffer->size[i];
3175 assert( totalmem == buffer->totalmem );
3176#endif
3177
3178 return (long long) buffer->totalmem;
3179}
3180
3181/** outputs statistics about currently allocated buffers to the screen */
3183 BMS_BUFMEM* buffer /**< memory buffer storage */
3184 )
3185{
3186 size_t totalmem;
3187 size_t i;
3188
3189 assert( buffer != NULL );
3190
3191 totalmem = 0UL;
3192 for (i = 0; i < buffer->ndata; ++i)
3193 {
3194 printf("[%c] %8llu bytes at %p\n", buffer->used[i] ? '*' : ' ', (unsigned long long)(buffer->size[i]), buffer->data[i]);
3195 totalmem += buffer->size[i];
3196 }
3197 printf(" %8llu bytes total in %llu buffers\n", (unsigned long long)totalmem, (unsigned long long)(buffer->ndata));
3198}
common defines and data types used in all packages of SCIP
#define NULL
Definition def.h:255
#define INLINE
Definition def.h:127
#define SCIP_UNUSED(x)
Definition def.h:416
#define SCIP_Bool
Definition def.h:98
#define MIN(x, y)
Definition def.h:231
#define SCIP_Real
Definition def.h:163
#define TRUE
Definition def.h:100
#define FALSE
Definition def.h:101
#define MAX(x, y)
Definition def.h:227
static assert(heur !=NULL)
if(SCIPgetNContVars(scip)+SCIPgetNContImplVars(scip)==SCIPgetNVars(scip))
while(!lperror &&!cutoff &&lpsolstat==SCIP_LPSOLSTAT_OPTIMAL &&(divedepth< 10||(divedepth< maxdivedepth &&heurdata->nlpiterations< maxnlpiterations &&objval< searchbound)) &&!SCIPisStopped(scip))
assert(minobj< SCIPgetCutoffbound(scip))
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:2998
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:2203
#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:2318
#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:2133
int BMSisAligned(size_t size)
Definition memory.c:777
void BMSclearBlockMemory_call(BMS_BLKMEM *blkmem, const char *filename, int line)
Definition memory.c:1803
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:2462
long long BMSgetBufferMemoryUsed(const BMS_BUFMEM *buffer)
Definition memory.c:3164
#define ALIGNMENT
Definition memory.c:697
void BMSfreeBufferMemory_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition memory.c:3111
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:2012
void BMSfreeMemoryNull_call(void **ptr, const char *filename, int line)
Definition memory.c:642
void BMSsetBufferMemoryArraygrowinit(BMS_BUFMEM *buffer, int arraygrowinit)
Definition memory.c:2638
static void unlinkChunk(CHUNK *chunk)
Definition memory.c:996
static uint32_t getHashNumber(size_t size)
Definition memory.c:1759
void BMSdestroyBufferMemory_call(BMS_BUFMEM **buffer, const char *filename, int line)
Definition memory.c:2593
#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:2955
static INLINE void BMSfreeBufferMemory_work(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition memory.c:3046
static size_t calcMemoryGrowSize(size_t initsize, SCIP_Real growfac, size_t num)
Definition memory.c:2655
#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:2288
static BMS_CHKMEM * findChkmem(const BMS_BLKMEM *blkmem, const void *ptr)
Definition memory.c:1736
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:2843
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:1973
#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:1860
void * BMSreallocBufferMemoryArray_call(BMS_BUFMEM *buffer, void *ptr, size_t num, size_t typesize, const char *filename, int line)
Definition memory.c:2976
#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:2338
long long BMSgetBlockMemoryAllocated_call(const BMS_BLKMEM *blkmem)
Definition memory.c:2258
void BMSclearMemory_call(void *ptr, size_t size)
Definition memory.c:536
long long BMSgetBlockMemoryUsed_call(const BMS_BLKMEM *blkmem)
Definition memory.c:2268
void BMSfreeBufferMemoryNull_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition memory.c:3134
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:1769
void * BMSallocClearBlockMemoryArray_call(BMS_BLKMEM *blkmem, size_t num, size_t typesize, const char *filename, int line)
Definition memory.c:1994
void * BMSduplicateBlockMemoryArray_call(BMS_BLKMEM *blkmem, const void *source, size_t num, size_t typesize, const char *filename, int line)
Definition memory.c:2111
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:2557
static INLINE void * BMSreallocBufferMemory_work(BMS_BUFMEM *buffer, void *ptr, size_t size, const char *filename, int line)
Definition memory.c:2883
static void unlinkEagerChunk(CHUNK *chunk)
Definition memory.c:1044
void BMSdestroyBlockMemory_call(BMS_BLKMEM **blkmem, const char *filename, int line)
Definition memory.c:1837
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:2278
void BMSprintBufferMemory(BMS_BUFMEM *buffer)
Definition memory.c:3182
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:1726
void * BMSallocClearBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition memory.c:1956
void * BMSallocBufferMemory_call(BMS_BUFMEM *buffer, size_t size, const char *filename, int line)
Definition memory.c:2823
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:2697
void * BMSallocBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition memory.c:1936
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
static static void alignSize(size_t *size)
Definition memory.c:757
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:2626
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:3021
void BMSdestroyChunkMemory_call(BMS_CHKMEM **chkmem, const char *filename, int line)
Definition memory.c:1540
void BMSgarbagecollectBlockMemory_call(BMS_BLKMEM *blkmem)
Definition memory.c:2224
void BMSfreeBlockMemory_call(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition memory.c:2181
void * BMSallocClearBufferMemoryArray_call(BMS_BUFMEM *buffer, size_t num, size_t typesize, const char *filename, int line)
Definition memory.c:2864
#define GARBAGE_SIZE
Definition memory.c:696
long long BMSgetBlockMemoryUnusedMax_call(const BMS_BLKMEM *blkmem)
Definition memory.c:2298
void * BMSduplicateBlockMemory_call(BMS_BLKMEM *blkmem, const void *source, size_t size, const char *filename, int line)
Definition memory.c:2091
#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:2052
size_t BMSgetNUsedBufferMemory(BMS_BUFMEM *buffer)
Definition memory.c:3154
long long BMSgetBlockMemoryAllocatedMax_call(const BMS_BLKMEM *blkmem)
Definition memory.c:2308
#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_BufMem BMS_BUFMEM
Definition memory.h:721
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 SCIPrbtreeDelete(root, node)
Definition rbtree.h:69
#define SCIPrbtreeInsert(r, p, c, n)
Definition rbtree.h:70
#define SCIP_DEF_RBTREE_FIND(NAME, KEYTYPE, NODETYPE, LT, GT)
Definition rbtree.h:90
#define FOR_EACH_NODE(type, n, r, body)
Definition rbtree.h:77
size_t * size
Definition memory.c:2545
unsigned int * used
Definition memory.c:2546
void ** data
Definition memory.c:2544
size_t firstfree
Definition memory.c:2550
double arraygrowfac
Definition memory.c:2551
unsigned int arraygrowinit
Definition memory.c:2552
unsigned int clean
Definition memory.c:2548
size_t totalmem
Definition memory.c:2547
size_t ndata
Definition memory.c:2549